package com.devo.icecream

import android.Manifest
import android.app.Activity
import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.os.Process
import android.text.format.DateUtils
import android.view.Gravity
import androidx.core.app.ActivityCompat
import androidx.core.content.edit
import androidx.core.content.getSystemService
import com.blankj.utilcode.util.ToastUtils
import com.devo.icecream.data.APIClient
import com.devo.icecream.data.PLCStatusBean
import com.devo.icecream.modbus.PLCConnectStatus
import com.devo.icecream.modbus.PLCManager
import com.devo.icecream.service.ActivityWatcherService
import com.devo.icecream.socket.SocketClient
import com.devo.icecream.utils.ActivityLifecycleListener
import com.devo.icecream.utils.LocationUtils
import com.devo.icecream.utils.MachineKeyInterceptor
import com.google.gson.Gson
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.CsvFormatStrategy
import com.orhanobut.logger.DiskLogAdapter
import com.orhanobut.logger.Logger
import com.tencent.bugly.crashreport.CrashReport
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collectLatest
import kotlin.time.DurationUnit
import kotlin.time.toDuration


typealias AppLogger = Logger

val AppToast =
    ToastUtils.make()
        .setTextSize(36)
        .setTextColor(Color.WHITE)
        .setGravity(Gravity.CENTER, 0, 50)
        .setBgColor(Color.GRAY)

class IceCreamApp : Application() {
    private val scope = CoroutineScope(Dispatchers.IO + Job())

    private var shutdownJob: Job? = null

    private val activityManager by lazy {
        getSystemService<ActivityManager>()
    }

    companion object {
        lateinit var preferences: SharedPreferences
        private lateinit var _instance: IceCreamApp


        @JvmStatic
        val activities = mutableMapOf<String, Boolean?>()
        val gson = Gson()
        var isNormal = true;
        fun get(): IceCreamApp = _instance

    }

    @OptIn(FlowPreview::class)
    override fun onCreate() {
        super.onCreate()
        _instance = this
        preferences = getSharedPreferences("app", MODE_PRIVATE)
        initLogger()

        if (getProcessName(this, Process.myPid()) != packageName) {
            return
        }

        initActivityCallback()
        watchPlcStatus()

        startService(Intent(this, ActivityWatcherService::class.java))

        with(scope) {
            launch {
                SocketClient.getMachineKeyChangeFlow().collect {
                    MachineKeyInterceptor.key = it.key
                    AppLogger.i("machine key is updated... :${it.key}")
                }
            }
            launch {
                preferences.edit {
                    var phone: String? = null
                    while (phone == null) {
                        try {
                            phone = APIClient.getServicePhone()
                        } catch (e: Exception) {
                            AppLogger.e(e, "获取服务电话报错")
                            delay(3_000)
                        }
                    }
                    putString("service_phone", phone)
                }
            }
//            launch {
//                SocketClient.getBusinessTimeChangedFlow().debounce(10000).collectLatest {
//                    val range = it.businessTimeDto.toRange().toDateRange()
//                    PLCManager.plcStatus?.setMaintains(System.currentTimeMillis() in range)
//                }
//            }
        }

        SocketClient.init()
        PLCManager.init(this)

        CrashReport.initCrashReport(this, "9d835cb0a5", BuildConfig.DEBUG)

        if (!preferences.contains("shutdown")) {
            preferences.edit(true) {
                putLong("shutdown", System.currentTimeMillis())
            }
        }
    }

    fun getProcessName(cxt: Context, pid: Int): String? {
        val am = cxt.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningApps = am.runningAppProcesses ?: return null
        for (procInfo in runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName
            }
        }
        return null
    }


    private fun initActivityCallback() {
        registerActivityLifecycleCallbacks(object : ActivityLifecycleListener() {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                super.onActivityCreated(activity, savedInstanceState)
                AppLogger.i("add ${activity.localClassName}")
                activities[activity.localClassName] = null
            }

            override fun onActivityStarted(activity: Activity) {
                super.onActivityStarted(activity)
                activities[activity.localClassName] = true
            }

            override fun onActivityStopped(activity: Activity) {
                super.onActivityStopped(activity)
                activities[activity.localClassName] = false
            }

            override fun onActivityDestroyed(activity: Activity) {
                super.onActivityDestroyed(activity)
                AppLogger.i("del ${activity.localClassName}")
                activities.remove(activity.localClassName)

                if (activities.isEmpty()) {
                    this@IceCreamApp.onDestroy()
                }
            }
        })
    }

    private fun initLogger() {

        AppLogger.addLogAdapter(object : AndroidLogAdapter() {
            override fun isLoggable(priority: Int, tag: String?): Boolean {
                return BuildConfig.DEBUG
            }
        })
        AppLogger.addLogAdapter(
            DiskLogAdapter(
                CsvFormatStrategy.newBuilder()
                    .tag("file_log")
                    .build()
            )
        )
    }

    private fun watchPlcStatus() {
        scope.launch {
            preferences.edit(true) {
                remove("content")
            }

            while (true) {
                delay(2_000)
                try {
                    preferences.edit {
                        val bean = PLCStatusBean(
                            buckets = PLCManager.plcStock?.getStockStatus()
                                ?: mapOf(),   //库存2获取库存状态【桶位信息】包括库存量 库存号
                            machine = PLCManager.plcStatus?.toJson() ?: mapOf(),//plc总运行状态 温度等信息实体类 设备信息
                            malfunction = PLCManager.plcMalfunction?.getMalfunctions()//故障码列表
                                ?.let {//状态查询结果
                                    return@let it.toMutableList().apply {
                                        // PLC 断开连接，告诉后端
                                        if (!PLCManager.isAvailable()) {
                                            add("DISCONNECT")
                                        }
                                        isNormal.takeIf { e -> !e }?.let {
                                            add("APP_STATUS")
                                        }

                                    }
                                } ?: listOf()
                        )
                        //socket心跳的时候获取
                        putString(
                            "content", gson.toJson(bean)
                        )
                    }
                } catch (e: Exception) {
                    AppLogger.e(e, "保存状态数据出错")
                }

            }
        }
        scope.launch {
            AppLogger.d("开始订阅PLC连接状态")
            PLCManager.connectionStatus.collectLatest {
                if (it == PLCConnectStatus.Disconnected) {
                    AppLogger.e("PLC未连接")
                    AppToast.show("PLC未连接")
                }
            }
        }

    }

    fun startDelayShutdown() {
        if (shutdownJob != null) {
            return
        }

        val shutdownTime = preferences.getLong("shutdown", System.currentTimeMillis())
        if (shutdownTime + DateUtils.HOUR_IN_MILLIS * 6 > System.currentTimeMillis()) {
            AppLogger.w("关机时间没到")
            return
        }

        shutdownJob = scope.launch {
            AppLogger.w("开始关机任务")
            delay(5.toDuration(DurationUnit.SECONDS))
            preferences.edit(true) {
                putLong("shutdown", System.currentTimeMillis())
            }

            delay(5.toDuration(DurationUnit.SECONDS))
            Process.killProcess(Process.myPid())
            shutdownJob = null
        }
    }

    private fun onDestroy() {

        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            LocationUtils.unregister()
        }
    }
}